#include "base/Cube.h"
#include <iostream>

float Cube::positionData[] =
{
     0.5f, -0.5f,  0.5f,
     0.5f, -0.5f, -0.5f,
     0.5f,  0.5f, -0.5f,
     0.5f,  0.5f,  0.5f,

     0.5f,  0.5f,  0.5f,
     0.5f,  0.5f, -0.5f,
    -0.5f,  0.5f, -0.5f,
    -0.5f,  0.5f,  0.5f,

    -0.5f,  0.5f,  0.5f,
    -0.5f,  0.5f, -0.5f,
    -0.5f, -0.5f, -0.5f,
    -0.5f, -0.5f,  0.5f,

    -0.5f, -0.5f,  0.5f,
     0.5f, -0.5f,  0.5f,
     0.5f, -0.5f, -0.5f,
    -0.5f, -0.5f, -0.5f,

     0.5f,  0.5f,  0.5f,
     0.5f, -0.5f,  0.5f,
    -0.5f, -0.5f,  0.5f,
    -0.5f,  0.5f,  0.5f,

     0.5f,  0.5f, -0.5f,
    -0.5f,  0.5f, -0.5f,
    -0.5f, -0.5f, -0.5f,
     0.5f, -0.5f, -0.5f
};

float Cube::normalData[] =
{
    1.0f,  0.0f,  0.0f,
    1.0f,  0.0f,  0.0f,
    1.0f,  0.0f,  0.0f,
    1.0f,  0.0f,  0.0f,

    0.0f,  1.0f,  0.0f,
    0.0f,  1.0f,  0.0f,
    0.0f,  1.0f,  0.0f,
    0.0f,  1.0f,  0.0f,

   -1.0f,  0.0f,  0.0f,
   -1.0f,  0.0f,  0.0f,
   -1.0f,  0.0f,  0.0f,
   -1.0f,  0.0f,  0.0f,

    0.0f, -1.0f,  0.0f,
    0.0f, -1.0f,  0.0f,
    0.0f, -1.0f,  0.0f,
    0.0f, -1.0f,  0.0f,

    0.0f,  0.0f,  1.0f,
    0.0f,  0.0f,  1.0f,
    0.0f,  0.0f,  1.0f,
    0.0f,  0.0f,  1.0f,

    0.0f,  0.0f, -1.0f,
    0.0f,  0.0f, -1.0f,
    0.0f,  0.0f, -1.0f,
    0.0f,  0.0f, -1.0f
};

//float Cube::textureData[] =
//{
//    0.0f,  0.0f,
//    1.0f,  0.0f,
//    1.0f,  1.0f,
//    0.0f,  1.0f,
//
//    0.0f,  0.0f,
//    1.0f,  0.0f,
//    1.0f,  1.0f,
//    0.0f,  1.0f,
//
//    0.0f,  0.0f,
//    1.0f,  0.0f,
//    1.0f,  1.0f,
//    0.0f,  1.0f,
//
//    0.0f,  0.0f,
//    1.0f,  0.0f,
//    1.0f,  1.0f,
//    0.0f,  1.0f,
//
//    0.0f,  0.0f,
//    1.0f,  0.0f,
//    1.0f,  1.0f,
//    0.0f,  1.0f,
//
//    0.0f,  0.0f,
//    1.0f,  0.0f,
//    1.0f,  1.0f,
//    0.0f,  1.0f,
//};

Cube::Cube(GLuint programHandler, GLShaderConfig shaderConfig) :
		GLObject(programHandler, shaderConfig) {
	GLShaderConfig* config = GLObject::getShaderConfig();

	/**
	 * POSITION DATA
	 */
	BufferConfig positionBuffer;
	positionBuffer.target = GL_ARRAY_BUFFER;
	positionBuffer.size = 3 * 24 * sizeof(float);
	positionBuffer.data = positionData;
	positionBuffer.usage = GL_STATIC_DRAW;

	VertexAttrib positionAttrib;
	positionAttrib.index = config->getVertexAttribIndex(GLShaderConfig::VERTEX_POSITION_TAG);
	positionAttrib.size = 3;
	positionAttrib.type = GL_FLOAT;
	positionAttrib.normalized = GL_FALSE;
	positionAttrib.stride = 0;
	positionAttrib.pointer = NULL;

	config->addVertexAttribInfo(GLShaderConfig::VERTEX_POSITION_TAG, positionAttrib, positionBuffer);

	/**
	 * NORMAL DATA
	 */
	BufferConfig normalBuffer;
	normalBuffer.target = GL_ARRAY_BUFFER;
	normalBuffer.size = 3 * 24 * sizeof(float);
	normalBuffer.data = normalData;
	normalBuffer.usage = GL_STATIC_DRAW;

	VertexAttrib normalAttrib;
	normalAttrib.index = config->getVertexAttribIndex(GLShaderConfig::VERTEX_NORMAL_TAG);
	normalAttrib.size = 3;
	normalAttrib.type = GL_FLOAT;
	normalAttrib.normalized = GL_FALSE;
	normalAttrib.stride = 0;
	normalAttrib.pointer = NULL;

	config->addVertexAttribInfo(GLShaderConfig::VERTEX_NORMAL_TAG, normalAttrib, normalBuffer);

//	/**
//	 * TEXTURE DATA
//	 */
//	BufferConfig textureBuffer;
//	textureBuffer.target = GL_ARRAY_BUFFER;
//	textureBuffer.size = 2 * 24 * sizeof(float);
//	textureBuffer.data = textureData;
//	textureBuffer.usage = GL_STATIC_DRAW;
//
//	VertexAttrib textureAttrib;
//	textureAttrib.index = config->getVertexAttribIndex(GLShaderConfig::VERTEX_TEXTURE_COORD_TAG);
//	textureAttrib.size = 2;
//	textureAttrib.type = GL_FLOAT;
//	textureAttrib.normalized = GL_FALSE;
//	textureAttrib.stride = 0;
//	textureAttrib.pointer = NULL;
//
//	config->addVertexAttribInfo(GLShaderConfig::VERTEX_TEXTURE_COORD_TAG, textureAttrib, textureBuffer);
};

void Cube::render(glm::mat4 viewMatrix, glm::mat4 modelMatrix) {

	changeObjectColor(colorR, colorG, colorB);
	// Normal Matrix
	glm::mat3 normal_matrix = glm::mat3 ( 1.0f );
	// normal_matrix =
	glm::mat4 aux = viewMatrix * modelMatrix * transformMatrix;
	for (int i=0; i<3; i++)
		for (int j=0; j<3; j++)
			normal_matrix[i][j] = aux[i][j];


	// Bind Object Transformation Matrix
	GLuint locationTransformMatrix = glGetUniformLocation( this->programHandler, "TransformMatrix");
	if( locationTransformMatrix >= 0 )
	{
		glUniformMatrix4fv( locationTransformMatrix, 1, GL_FALSE, &transformMatrix[0][0]);
	}

	// Bind Model Matrix
	GLuint locationModelMatrix = glGetUniformLocation( this->programHandler, "ModelMatrix");
	if( locationModelMatrix >= 0 )
	{
		glUniformMatrix4fv( locationModelMatrix, 1, GL_FALSE, &modelMatrix[0][0]);
	}

	// Bind View MAtrix
	GLuint locationViewMatrix = glGetUniformLocation( this->programHandler, "ViewMatrix");
	if( locationViewMatrix >= 0 )
	{
		glUniformMatrix4fv( locationViewMatrix, 1, GL_FALSE, &viewMatrix[0][0]);
	}

	// Bind Normal MAtrix
	GLuint locationNormalMatrix = glGetUniformLocation( this->programHandler, "NormalMatrix");
	if( locationNormalMatrix >= 0 )
	{
		glUniformMatrix3fv( locationNormalMatrix, 1, GL_FALSE, &normal_matrix[0][0]);
	}

	glBindVertexArray( vaoHandler );
	glDrawArrays(GL_QUADS, 0, 24);
}

void Cube::update(glm::mat4 viewMatrix, glm::mat4 modelMatrix) {
	init();
	render(viewMatrix, modelMatrix);
}

void Cube::setTextureData(float diffuseTexture[], float dirtTexture[]) {
	GLShaderConfig* config = GLObject::getShaderConfig();

	/**
	 * TEXTURE DATA
	 */
	if (diffuseTexture != NULL) {
		BufferConfig textureBuffer;
		textureBuffer.target = GL_ARRAY_BUFFER;
		textureBuffer.size = 2 * 24 * sizeof(float);
		textureBuffer.data = diffuseTexture;
		textureBuffer.usage = GL_STATIC_DRAW;

		VertexAttrib textureAttrib;
		textureAttrib.index = config->getVertexAttribIndex(GLShaderConfig::VERTEX_DIFFUSE_TEXTURE_COORD_TAG);
		textureAttrib.size = 2;
		textureAttrib.type = GL_FLOAT;
		textureAttrib.normalized = GL_FALSE;
		textureAttrib.stride = 0;
		textureAttrib.pointer = NULL;

		config->addVertexAttribInfo(GLShaderConfig::VERTEX_DIFFUSE_TEXTURE_COORD_TAG, textureAttrib, textureBuffer);
		this->useDiffuseTexture = true;
	}

	if (dirtTexture != NULL) {
		BufferConfig textureBuffer2;
		textureBuffer2.target = GL_ARRAY_BUFFER;
		textureBuffer2.size = 2 * 24 * sizeof(float);
		textureBuffer2.data = dirtTexture;
		textureBuffer2.usage = GL_STATIC_DRAW;

		VertexAttrib textureAttrib2;
		textureAttrib2.index = config->getVertexAttribIndex(GLShaderConfig::VERTEX_DIRT_TEXTURE_COORD_TAG);
		textureAttrib2.size = 2;
		textureAttrib2.type = GL_FLOAT;
		textureAttrib2.normalized = GL_FALSE;
		textureAttrib2.stride = 0;
		textureAttrib2.pointer = NULL;

		config->addVertexAttribInfo(GLShaderConfig::VERTEX_DIRT_TEXTURE_COORD_TAG, textureAttrib2, textureBuffer2);
		this->useDirtTexture = true;
	}
}
